"""
Author: yongfa
Date: 2020-12-22 11:26:51
LastEditTime  2023-01-03 17:17:47
LastEditors   yongfa
Description: 文件上传
"""

import os

import uuid
import time
from flask import current_app
from PIL import Image
import filetype

from app.extensions.exception import Failed, FileExtensionException, FileTooLargeException


class Uploader(object):

    def __init__(self) -> None:
        self.STATIC_LOCAL_URL = current_app.config.get('STATIC_LOCAL_URL')
        self.UPLOAD_FOLDER = current_app.config.get('UPLOAD_FOLDER')
        self.ALLOWED_EXTENSIONS = current_app.config.get('ALLOWED_EXTENSIONS')
        self.MAX_CONTENT_LENGTH = current_app.config.get('MAX_CONTENT_LENGTH')

    def allowed_file(self, filename: str) -> bool:
        return '.' in filename and \
            filename.rsplit('.', 1)[1].lower() in self.ALLOWED_EXTENSIONS

    def replace_path(self, file_name: str) -> str:
        """替换为静态url地址"""
        return file_name.replace(self.UPLOAD_FOLDER, self.STATIC_LOCAL_URL)

    def replace_folder_path(self, file_name):
        """替换为绝对位置地址"""

        file_path = ''

        if current_app.config.get('STATIC_LOCAL_URL') in file_name:
            file_path = file_name.replace(self.STATIC_LOCAL_URL, self.UPLOAD_FOLDER)
        else:
            # 使用os.path.join第二个参数的首个字符如果是"/" , 拼接出来的路径会不包含第一个参数
            if file_name.index('/') == 0:
                file_name = file_name[1:]
            file_path = os.path.join(self.UPLOAD_FOLDER, file_name)

        return file_path

    def cut_path(self, file_path):
        """截断文件地址， 包括静态和绝对地址"""
        for path in [self.STATIC_LOCAL_URL, self.UPLOAD_FOLDER]:
            if path in file_path:
                return file_path.replace(path, '')
            else:
                return file_path

    def get_file_size(self, file_path):
        """获取文件大小, 单位MB"""

        fsize = os.path.getsize(file_path)
        fsize = fsize / float(1024 * 1024)
        if fsize > self.MAX_CONTENT_LENGTH:
            raise FileTooLargeException()
        return round(fsize, 2)

    @staticmethod
    def rename_file(old_filename):
        """重命名文件名"""
        ext = os.path.splitext(old_filename)[1]
        new_filename = uuid.uuid4().hex + ext
        return new_filename

    @staticmethod
    def compress_file(file_path: str) -> str:
        """[压缩图片]

        Args:
            file_path (str): [文件路径]

        Returns:
            str: [压缩后的文件路径]
        """
        img = Image.open(file_path)
        x, y = img.size
        x_s = 350
        y_s = int(y * x_s / x)
        img = img.resize((x_s, y_s), Image.ANTIALIAS)
        img = img.convert('RGB')
        small_path = file_path.rsplit('.', 1)[0] + '-350.' + file_path.rsplit('.', 1)[1].lower()
        img.save(small_path)

        return small_path

    @ staticmethod
    def get_file_type(file_path: str) -> str:
        """[获取文件类型]

        Args:
            file_path (str): [文件路径]

        Returns:
            str: [文件类型]
        """
        try:

            kind = filetype.guess(file_path)
            if kind is None:
                return '未知类型'
            return kind.mime
        except Exception as e:
            current_app.logger.error('判断文件类型错误' + str(e))
            return '未知类型'

    def save_file(self, module_name, file):
        """
        保存文件, 按照模块名+时间分类
        """
        upload_path = os.path.join(self.UPLOAD_FOLDER, module_name)
        time_str = time.strftime("%Y-%m-%d-%H", time.localtime())

        dir_path = os.path.join(upload_path, time_str)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        filename = self.rename_file(file.filename)
        file_path = os.path.join(dir_path, filename)

        file.save(file_path)  # 保存图片
        file_type = self.get_file_type(file_path)
        file_size = self.get_file_size(file_path)
        small_path = ''
        # 若为图片，压缩
        if 'image' in file_type:
            small_path = self.compress_file(file_path)

        file_info = {
            'file_path': self.replace_path(file_path),
            'file_small_path': self.replace_path(small_path),
            'filename': filename,
            'name': file.filename,
            'file_size': file_size,
            'file_type': file_type,
            'file_cate': module_name
        }
        return file_info

    def upload_files(self, module_name, file=None):
        """上传文件"""
        if file is not None:
            if not self.allowed_file(file.filename):
                raise FileExtensionException()
            else:
                return self.save_file(module_name, file)

        return Failed(message='需要携带文件')

    def delete_files(self, file_url: list):
        """删除文件"""

        try:
            for file_path in list(map(self.replace_folder_path, file_url)):
                small_path = file_path.rsplit('.', 1)[0] + '-350.' + file_path.rsplit('.', 1)[1].lower()
                if os.path.exists(file_path):
                    os.remove(file_path)
                if os.path.exists(small_path):
                    os.remove(small_path)
        except Exception as e:
            current_app.logger.error('删除文件{}错误,'.format(str(file_url)) + str(e))
